import functools
import inspect
from collections import deque

from thread_project.demo08.wrapper import CoroutineWrapper


def coroutine(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        gen = func(*args, **kwargs)
        if inspect.isgenerator(gen):
            coro = CoroutineWrapper(YieldLoop.instance(), gen)
            return coro
        else:
            raise RuntimeError("[CoroutineWrapper] error."
                               "type({}) is not supporter".format(type(gen)))
    return wrapper


class YieldLoop:
    current = None
    runnables = deque()

    # 单例模式
    @classmethod
    def instance(cls):
        if not YieldLoop.current:
            YieldLoop.current = YieldLoop()
        return YieldLoop.current

    def add_runnables(self, coro):
        self.runnables.append(coro)

    def add_coroutine(self, coro):
        assert isinstance(coro, CoroutineWrapper), "isinstance(coro) != CoroutineWrapper"
        self.add_runnables(coro)

    def run_coroutine(self, coro):
        try:
            # print("run coro:{}".format(coro))
            coro.send(coro.context)
        except StopIteration as e:
            print("coroutine {} stop.".format(coro))

    def run_until_complete(self):
        while YieldLoop.runnables:
            # print("runnables:{}".format(YieldLoop.runnables))
            coro = YieldLoop.runnables.popleft()
            self.run_coroutine(coro)
